﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using ApiDoc.Extensions;

namespace ApiDoc
{
    /// <summary>
    /// Base for Documentation classes for members that wrap MemberInfo types.
    /// </summary>
    public abstract class MemberDocumentationBase<T>
        where T : MemberInfo
    {
        public MemberDocumentationBase(T member, ApiDocumentationManager manager)
        {
            Member = member;
            Manager = manager;
        }

        /// <summary>
        /// Gets the cref for the member.
        /// </summary>
        public string CRef
        {
            get
            {
                if (m_cref == null) {
                    m_cref = ApiDoc.CRef.ReflectionCRefGenerator.NoPrefix.GetCRef(Member);
                }

                return m_cref;
            }
        }

        private string m_cref;

        /// <summary>
        /// Returns the member.
        /// </summary>
        protected internal T Member { get; protected set; }

        /// <summary>
        /// Returns the member.
        /// </summary>
        protected ApiDocumentationManager Manager { get; set; }

        public string ILName
        {
            get
            {
                return Member.Name;
            }
        }

        /// <summary>
        /// Gets the description from the XML documentation.
        /// </summary>
        public MarkupString Description
        {
            get
            {
                var element = Manager.GetXmlDocumentation(Member);
                if (element == null) {
                    // TODO have an option that causes us to look up overriden methods or namespace methods for documentation.
                    return MarkupString.Create(String.Empty, (IMemberDocumentation)this, Manager);
                }

                var summary = element.Element("summary");
                if (summary == null) {
                    return MarkupString.Create(String.Empty, (IMemberDocumentation)this, Manager);
                }

                return MarkupString.Create(summary.GetInnerXml(), (IMemberDocumentation)this, Manager);
            }
        }

        /// <summary>
        /// Gets the remarks from the XML documentation.
        /// </summary>
        public MarkupString Remarks
        {
            get
            {
                var element = Manager.GetXmlDocumentation(Member);
                if (element == null) {
                    // TODO have an option that causes us to look up overriden methods or namespace methods for documentation.
                    return MarkupString.Create(String.Empty, (IMemberDocumentation)this, Manager);
                }

                var remarks = element.Elements("remarks");
                if (!remarks.Any()) {
                    return MarkupString.Create(String.Empty, (IMemberDocumentation)this, Manager);
                }

                var ret = new StringBuilder();
                foreach (var remark in remarks) {
                    ret.AppendLine(remark.GetInnerXml());
                }

                return MarkupString.Create(ret.ToString(), (IMemberDocumentation)this, Manager);
            }
        }

        /// <summary>
        /// Gets the examples from the XML documentation.
        /// </summary>
        public MarkupString Example
        {
            get
            {
                var element = Manager.GetXmlDocumentation(Member);
                if (element == null) {
                    // TODO have an option that causes us to look up overriden methods or namespace methods for documentation.
                    return MarkupString.Create(String.Empty, (IMemberDocumentation)this, Manager);
                }

                var remarks = element.Elements("example");
                if (!remarks.Any()) {
                    return MarkupString.Create(String.Empty, (IMemberDocumentation)this, Manager);
                }

                var ret = new StringBuilder();
                foreach (var remark in remarks) {
                    ret.AppendLine(remark.GetInnerXml());
                }

                return MarkupString.Create(ret.ToString(), (IMemberDocumentation)this, Manager);
            }
        }

        /// <summary>
        /// Gets the examples from the XML documentation.
        /// </summary>
        public MarkupString SeeAlso
        {
            get
            {
                var element = Manager.GetXmlDocumentation(Member);
                if (element == null) {
                    // TODO have an option that causes us to look up overriden methods or namespace methods for documentation.
                    return MarkupString.Create(String.Empty, (IMemberDocumentation)this, Manager);
                }

                var remarks = element.Elements("seealso");
                if (!remarks.Any()) {
                    return MarkupString.Create(String.Empty, (IMemberDocumentation)this, Manager);
                }

                var ret = new StringBuilder();
                foreach (var remark in remarks) {
                    ret.AppendLine(remark.GetInnerXml());
                }

                return MarkupString.Create(ret.ToString(), (IMemberDocumentation)this, Manager);
            }
        }
    }
}
